﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "InplaceEditProcessChatServer.h"
#include "GmCommunicationProtocolUtils.h"
#include "RpcSharedObject.h"
#include <QWidget>
#include <QEvent>
#include <QTimer>
#include "IApplication.h"
#include "IMainWindow.h"
#include "GbmpNew.h"
#include "DebugMessage.h"

#include "JournalUtils.h"
#include "IJournalClient.h"
#include "InplaceEditProjectJournalMessageSender.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace
{
    bool IsProcessRunning(PROCESS_INFORMATION* pProcess)
    {
        DWORD exitCode = 0;
        BOOL isOk = GetExitCodeProcess(pProcess->hProcess, &exitCode);
        if (isOk && exitCode == STILL_ACTIVE)
        {
            return true;
        }
        return false;
    }
}

InplaceEditProcessChatServer& gcmp::InplaceEditProcessChatServer::GetInstance()
{
    static InplaceEditProcessChatServer chatServer;
    return chatServer;
}

InplaceEditProcessChatServer::InplaceEditProcessChatServer()
    : m_pMainWindow(nullptr)
    , m_pMaskWidget(NEW_AS_QT(QWidget))
    , m_familyPort(0)
    , m_pTimer(nullptr)
{
    m_pMainWindow = dynamic_cast<QWidget*>(IMainWindow::GetMainWindow());
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_pMainWindow, L"mainWindow为空",L"GDMPLab",L"2024-03-30");

    m_pMaskWidget->setParent(m_pMainWindow);
    m_pMaskWidget->hide();
    m_pTimer = NEW_AS_QT(QTimer, this);
    m_pTimer->setInterval(500);
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(TimeOutSlot()));
}

bool InplaceEditProcessChatServer::eventFilter(QObject* pWatched, QEvent* pEvent)
{
    if (pWatched == m_pMainWindow)
    {
        const QEvent::Type eventType = pEvent->type();
        if ((eventType == QEvent::WindowActivate) || (eventType == QEvent::WindowStateChange) || (eventType == QEvent::Close))
        {
            pEvent->ignore();
            m_pMainWindow->setWindowState(Qt::WindowMinimized);
            ActivateFamilyWindow();
            return true;
        }
        return false;
    }
    else
    {
        return QObject::eventFilter(pWatched, pEvent);
    }
}

void InplaceEditProcessChatServer::Start(OwnerPtr<PROCESS_INFORMATION> opProcess)
{
    m_opProcess = TransferOwnership(opProcess);

    auto startTask = [=]() {
        m_pMainWindow->installEventFilter(this);
        m_pMainWindow->setWindowState(Qt::WindowMinimized);
        ShowMask();
        StartTimer();
    };

    startTask();

    // 日志请求协作
    IJournalClient::Get()->InitRequestContext();
}

void gcmp::InplaceEditProcessChatServer::StartTimer()
{
    m_pTimer->start();
}

void InplaceEditProcessChatServer::Stop()
{
    if (m_pMainWindow)
    {
        m_pMainWindow->removeEventFilter(this);
    }
    HideMask();
    m_pTimer->stop();
    SetFamilyPort(0); // 重置族App端口

    //重置进程
    if (m_opProcess)
    {
        CloseHandle(m_opProcess->hThread);
        CloseHandle(m_opProcess->hProcess);
        m_opProcess = nullptr;
    }

    // 日志结束协作
    IJournalClient::Get()->FinishCooperation();
}

uint16_t InplaceEditProcessChatServer::GetFamilyPort()
{
    return m_familyPort;
}

void InplaceEditProcessChatServer::SetFamilyPort(uint16_t familyPort)
{
    m_familyPort = familyPort;
}

void InplaceEditProcessChatServer::ActivateFamilyWindow()
{
    if (this->GetFamilyPort() != 0)
    {
        CommunicationProtocolUtils::SendIpcMessage(this->GetFamilyPort(), FunctionType::InPlaceEdit, OperationType::ActivateFamilyWindow, nullptr);
    }
}

void InplaceEditProcessChatServer::ShowMask()
{
    if (!m_pMaskWidget->isVisible())
    {
        m_pMaskWidget->setGeometry(m_pMainWindow->geometry());
        m_pMaskWidget->setStyleSheet("background-color: rgba(0, 0, 0, 128)");
        m_pMaskWidget->show();
    }
}

void InplaceEditProcessChatServer::HideMask()
{
    m_pMaskWidget->hide();
}

void gcmp::InplaceEditProcessChatServer::TimeOutSlot()
{
    bool isFailed = false;
    if (m_familyPort == 0) // 族App还没有启动完成，只需检测族进程是否存在
    {
        if (m_opProcess && !IsProcessRunning(m_opProcess.get()))
        {
            isFailed = true;
        }
    }
    else // 族App已经启动就绪，发送心跳包检测
    {
        OwnerPtr<RpcServerInfo> opServerInfo = CommunicationProtocolUtils::SendHeartBeat(this->GetFamilyPort());
        if (!opServerInfo)
        {
            isFailed = true;
        }
    }
    if (isFailed)
    {
        Stop();

        // 最大化主窗口
        QWidget* pWidget = dynamic_cast<QWidget*>(IMainWindow::GetMainWindow());
        DBG_WARN_AND_RETURN_VOID_UNLESS(pWidget, L"pWidget为空",L"GDMPLab",L"2024-03-30");
        pWidget->setWindowState(Qt::WindowMaximized);
    }
}
